package com.david.viewtest.widget

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.content.res.Resources
import android.os.Build
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.core.animation.doOnEnd
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.david.viewtest.R
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlin.math.abs

class DragFloatWidget {
    /**
     * 悬浮父控件
     */
    var parent: View
    /**
     * 悬浮控件顶部拖动按钮
     */
    private var topImg: ImageView
    /**
     * 父控件layoutParam用于设置marginTop控制上边距
     */
    var param: FrameLayout.LayoutParams
    /**
     * 列表控件layoutParam，用于设置列表高度使列表都可滑动至底部
     */
    lateinit var listParam: FrameLayout.LayoutParams
    /**
     * 列表控件
     */
    private lateinit var recyclerView: RecyclerView

    /**
     * 按下开始y坐标
     */
    private var startY = 0f
    /**
     * 拖动/动画执行时的当前y坐标
     */
    private var currentY = 0

    /**
     * 移动多远后执行动画切换type
     */
    var changeOffset = 130

    /**
     * 父控件顶边距
     */
    private var topMargin = 0
    /**
     * 列表控件最大高度
     */
    var maxHeight = 0

    /**
     * 半屏时的顶边距
     */
    private var halfMargin = 0
    /**
     * 半屏时的列表高度
     */
    var halfHeight = dp2px(350f).toInt()

    /**
     * 最小化时的顶边距，最小不可见时设置大于屏幕高度即可
     */
    private var bottomMargin = 0
    /**
     * 最小化时的列表高度
     */
    private var minHeight = 0

    /**
     * 底部到半屏时的动画时间
     */
    private var minToHalfTime = 400L
    /**
     * 半屏到全屏的动画时间
     */
    private var halfToMaxTime = 700L

    /**
     * 手指按下时间
     */
    private var touchDownTime = 0L
    /**
     * 手指按下时的marginTop
     */
    private var touchDownMargin = 0

    /**
     * 当前的状态
     */
    private var type = BottomSheetBehavior.STATE_HIDDEN//0 收起, 1 半屏, 2 全屏

    /**
     * 事件回调
     */
    var bottomSheetCallback: DiscoverBottomSheetCallback? = null


    @SuppressLint("ClickableViewAccessibility")
    constructor(parent: FrameLayout, topAnchor: View, activity: Activity) {
        this.parent = parent
        topImg = parent.findViewById(R.id.anim_img)
        param = parent.layoutParams as FrameLayout.LayoutParams

        if(topAnchor.height == 0){//未布局好时延迟500ms初始化尺寸数据
            topAnchor.postDelayed({
                initSize(topAnchor, activity)
            }, 500)
        } else {
            initSize(topAnchor, activity)
        }


        initRecy()

        topImg.setOnTouchListener(object : View.OnTouchListener{
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                when(event?.action) {
                    MotionEvent.ACTION_DOWN -> {
                        startY = event.getY(0)
                        touchDownTime = System.currentTimeMillis()
                        touchDownMargin = param.topMargin
                    }
                    MotionEvent.ACTION_MOVE -> {
                        currentY = param.topMargin

                        param.topMargin = param.topMargin + (event.getY(0) - startY).toInt()
                        parent.layoutParams = param

                        //param.topMargin包含topAnchor的高度及marginTop，所以加上最初的topMargin
                        listParam.height = maxHeight - param.topMargin -topImg.height + topMargin
                        recyclerView.layoutParams = listParam

                        bottomSheetCallback?.onDragging(this@DragFloatWidget.parent, param.topMargin - currentY, listParam.height + topImg.height, type)
                    }
                    MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                        if((System.currentTimeMillis() - touchDownTime) < 200 && abs(touchDownMargin - param.topMargin) < 10){
                            //点击事件
                            bottomSheetCallback?.onHeaderClick(this@DragFloatWidget.parent, listParam.height + topImg.height, type)
                            return true
                        }


                        var time = 0L
                        val destination = when(type) {
                            BottomSheetBehavior.STATE_HIDDEN ->{
                                if (param.topMargin < (bottomMargin - changeOffset)) {
                                    type = BottomSheetBehavior.STATE_HALF_EXPANDED

                                    time = ((param.topMargin - halfMargin).toFloat() / (bottomMargin - halfMargin) * minToHalfTime).toLong()

                                    halfMargin
                                } else {

                                    time = ((bottomMargin - param.topMargin).toFloat() / (bottomMargin - halfMargin) * minToHalfTime).toLong()

                                    bottomMargin
                                }
                            }
                            BottomSheetBehavior.STATE_HALF_EXPANDED -> {
                                if (param.topMargin < (halfMargin - changeOffset)) {
                                    type = BottomSheetBehavior.STATE_EXPANDED

                                    time = ((param.topMargin - topMargin).toFloat() / (halfMargin - topMargin) * halfToMaxTime).toLong()

                                    topMargin
                                } else if (param.topMargin > (halfMargin + changeOffset)){
                                    type = BottomSheetBehavior.STATE_HIDDEN

                                    time = ((bottomMargin - param.topMargin).toFloat() / (bottomMargin - halfMargin) * minToHalfTime).toLong()

                                    bottomMargin
                                } else {
                                    time = ((abs(param.topMargin - halfMargin)).toFloat() / halfMargin * minToHalfTime).toLong()


                                    halfMargin
                                }
                            }
                            BottomSheetBehavior.STATE_EXPANDED -> {
                                if (param.topMargin > topMargin + changeOffset) {
                                    type = BottomSheetBehavior.STATE_HALF_EXPANDED

                                    time = ((halfMargin - param.topMargin).toFloat() / (halfMargin - topMargin) * halfToMaxTime).toLong()

                                    halfMargin
                                } else {
                                    time = ((abs(param.topMargin - topMargin)).toFloat() / topMargin * halfToMaxTime).toLong()

                                    topMargin
                                }
                            }
                            else -> bottomMargin
                        }

                        startFling(time , param.topMargin,  destination)
                    }
                }
                return true
            }

        })
    }

    /**
     * 计算相关尺寸
     */
    private fun initSize(topAnchor: View, activity: Activity) {
        val location = IntArray(2)
        topAnchor.getLocationInWindow(location)

        val dm = DisplayMetrics()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            activity.display?.getRealMetrics(dm)

//            activity.windowManager.currentWindowMetrics.bounds.height()
        } else {
            activity.windowManager.defaultDisplay.getRealMetrics(dm);
        }
//        var dwidth = dm.widthPixels;
        val dheight = dm.heightPixels

        val marginTop = location[1] + topAnchor.height

        this.maxHeight = dheight - marginTop

        topMargin = topAnchor.top + topAnchor.height
        halfMargin = topMargin + maxHeight - halfHeight
        bottomMargin = topMargin + maxHeight - minHeight
        param.topMargin = bottomMargin//开始为hidden隐藏,设置marginTop为bottomMargin


        param.height = this.maxHeight
        parent.layoutParams = param


        listParam.height = maxHeight - topImg.height
        recyclerView.layoutParams = listParam
    }

    /**
     * 开始执行动画
     */
    private fun startFling(time: Long, start: Int, destination: Int) {
        val valueAnimator: ValueAnimator =
            ValueAnimator.ofInt(start, destination).setDuration(if (time > 0) time else 100)
        valueAnimator.interpolator = LinearInterpolator()

        currentY = start
        valueAnimator.addUpdateListener { animation ->
            param.topMargin = animation.animatedValue as Int
            parent.layoutParams = param

            listParam.height = (maxHeight - param.topMargin -topImg.height + topMargin)
            recyclerView.layoutParams = listParam

            bottomSheetCallback?.onFling(this@DragFloatWidget.parent,param.topMargin - currentY,listParam.height + topImg.height, type)
            currentY = param.topMargin
        }

        valueAnimator.doOnEnd {
            bottomSheetCallback?.onAnimEnd(parent, listParam.height + topImg.height, type)
            val location = IntArray(2)
            recyclerView.getLocationInWindow(location)
        }

        valueAnimator.start()
    }

    /**
     * 初始化列表控件
     */
    private fun initRecy() {
        recyclerView = parent.findViewById(R.id.recy)
        listParam = recyclerView.layoutParams as FrameLayout.LayoutParams
        recyclerView.layoutManager = LinearLayoutManager(parent.context)
        recyclerView.adapter = AnimAdapter()

        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    //设置第一条完整显示
                    val layoutManager = recyclerView.layoutManager as LinearLayoutManager
                    val firstPosition = layoutManager.findFirstVisibleItemPosition()
                    //设置第一条完整显示
//                    val completePosition = layoutManager.findFirstCompletelyVisibleItemPosition()
//                    if (completePosition != firstPosition) {
//                        recyclerView.smoothScrollToPosition(firstPosition)
//                    }
                }
            }
        })

//        val snapHelper = PagerSnapHelper()
//        snapHelper.attachToRecyclerView(recyclerView)
    }

    /**
     * 滑动到某一状态
     */
    fun animToState(state:Int){
        if (state == type) {
            return
        }
        when(state){
            BottomSheetBehavior.STATE_HIDDEN -> {
                type = BottomSheetBehavior.STATE_HIDDEN
                startFling(300, param.topMargin, bottomMargin)
            }
            BottomSheetBehavior.STATE_HALF_EXPANDED -> {
                type = BottomSheetBehavior.STATE_HALF_EXPANDED
                startFling(300, param.topMargin, halfMargin)
            }
            BottomSheetBehavior.STATE_EXPANDED -> {
                type = BottomSheetBehavior.STATE_EXPANDED
                startFling(300, param.topMargin, topMargin)
            }
        }
    }

    private fun dp2px(dp: Float): Float {
        val r = Resources.getSystem()
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.displayMetrics)
    }
}

interface DiscoverBottomSheetCallback {
    /**
     * bottomSheet：底部浮动窗父布局
     * eachDistance：拖动时每次变动的距离, 正数时为向下移动
     * offset：距离手指按下的距离
     * parentHeight：bottomSheet的高度
     * currentState：当前状态
     */
    fun onDragging(bottomSheet: View, eachDistance: Int, listHeight: Int, currentState: Int)
    fun onFling(bottomSheet: View, eachDistance: Int, listHeight: Int, newState: Int)
    fun onAnimEnd(bottomSheet: View, parentHeight: Int, newState: Int)
    fun onHeaderClick(bottomSheet: View, listHeight: Int, currentState: Int)
}

class AnimAdapter: RecyclerView.Adapter<AnimHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnimHolder {
        val title = TextView(parent.context)
        title.setPadding(0, 30, 0, 30)
        return AnimHolder(title)
    }

    override fun onBindViewHolder(holder: AnimHolder, position: Int) {
        holder.title.text = "position is $position"
    }

    override fun getItemCount(): Int {
        return 50
    }

}

class AnimHolder(var title: TextView): RecyclerView.ViewHolder(title){
}